/**
 *
 * @author Jaime Moreno Reynold Rondez Chris  Sterling  Eric McDonald
 * 
 *  Developed as a team based project for a course at the California State  University of Monterey Bay by Reynold Rondez, Jaime Moreno, Chris  Sterling, Eric McDonald
 *  Dungeon Master is modeled after Zelda.
 */

import java.awt.*;
import java.util.ArrayList;
import java.awt.event.*;
import java.awt.geom.*; // for Java 2D stuff
import java.applet.*;
import java.net.URL;
import java.util.*;
import java.lang.Math;

public class DungeonMaster extends Applet implements Runnable,KeyListener,MouseListener{
	private static final long serialVersionUID=7645822198859243768L;
	private Random rand=new Random();
	
    //the main game loop thread
    private Thread gameLoop;
    
    //Control Keys are defined here.
    private int cUp=KeyEvent.VK_W, cDown=KeyEvent.VK_S, cLeft=KeyEvent.VK_A, cRight=KeyEvent.VK_D,
    cPause=KeyEvent.VK_P, cAttack=KeyEvent.VK_J, cAction=KeyEvent.VK_K, cSpecial=KeyEvent.VK_G,
    cItem=KeyEvent.VK_L;
    //Active Control Keys
    private boolean aUp=false, aDown=false, aLeft=false, aRight=false,  aAttack=false,
    aAction=false, aSpecial=false, aItem=false;
	private static HashMap<String,Image> imageCache=new HashMap<String,Image>();
	private static HashMap<String, AudioClip> audioCache = new HashMap<String, AudioClip>();
	private ArrayList<Character> characters = new ArrayList<Character>();
	private ArrayList<Player> players = new ArrayList<Player>();
	private ArrayList<Item> items = new ArrayList<Item>();
	private ArrayList<Arrow> arrows = new ArrayList<Arrow>();
	private Player player;
	private int score = 0;
	private int highScore = 0;
	private int gameLevel = 1; // start off with first level
	private int finalLevel = 5; // can change this to however many we come up with
	private static int knights = 4;
	

	private static int height = 600;
	private static int width = 840;
	
    //game pause state
	// allows you to stop the game
	
    private boolean gamePaused = false; // used as a toggle 
    public boolean gamePaused() { return gamePaused; }
    public void pauseGame() { gamePaused = true; }
    public void resumeGame() { gamePaused = false; }
    
    //game states
    // should probably use an enum here?
    
    final int GAME_MENU = 0;
    final int GAME_RUNNING = 1;
    final int GAME_OVER = 2;
    final int GAME_PAUSED = 3;
    final int GAME_WON = 4;
    
    int gameState = GAME_MENU; // start off with game menu
    
    private Image doubleBuffer; // added double buffer back in to fix flickering


    public void init(){//Applet uses init instead of main like a regular java program

        addKeyListener(this);
        //thread.start();
        gameStartup();
    }
    
    /**
     * gameStartup event 
     *****************************************************/
    void gameStartup() {
        //load sounds and music
        //load the health/shield bars
        //load powerups
        //load the background image
        //create the player sprite--first in the sprite list
        setImageCache();
        setPlayer();
        setItems();
        setEnemies();
        

        //start off in pause mode
        pauseGame();
    }
    
    /**
     * gameStartNewLevel event 
     *****************************************************/
    void gameStartNewLevel() {
        //load sounds and music
        //load the health/shield bars
        //load powerups
        //load the background image
        //create the player sprite--first in the sprite list
    	// customize this for new level
        if(gameLevel != 1) // don't want to call on inital level since will create duplicate characters!
        {
        	setItems();
        	setEnemies();
        }

    }

    /**
     * set up the characters for a level, including the player, enemies, and potions
     *****************************************************/
    
    //set up the player
    public void setPlayer() {
    	if(player == null){
    	player=new Player();
        players.add(player);
    	}
		
	}   
    
    public int getRandX()
    {
    	int x;
    	int minX = 100;
    	int maxX = 630;
    	do {
    		x = rand.nextInt(width);
    	}
    	while((x<minX) || (x>maxX));
    	return x;
    }
    public int getRandY()
    {
    	int minY = 100;
    	int maxY = 480;
    	int y;
    	do {
    		y = rand.nextInt(height);
    	}
    	while((y<minY) || (y>maxY));
    	return y;
    }


    public void addKnight()
    {
    	int x;
    	int y;
    	
    	x = getRandX();
    	y = getRandY();

    	Knight knight = new Knight(x,y);
    	characters.add(knight);
    }
    public void setEnemies() {
    	
        for(int i=0; i<knights; i++)
        {
        	addKnight();
        }

		
	}
    
    public void setItems() {
        HealthPotion healthPotion = new HealthPotion(getRandX(),getRandY(),25);
        StaminaPotion staminaPotion = new StaminaPotion(getRandX(),getRandY(),25);
        Bow bow = new Bow(getRandX(), getRandY());
        items.add(healthPotion);
        items.add(staminaPotion);
        if(!player.getBowAttack())
        {
        	items.add(bow);
        }
    
    }
    
    /**
     * thread start event - start the game loop running
     *****************************************************/
    public void start() {
        gameLoop = new Thread(this);
        gameLoop.start();
    }
    
    /**
     * thread run event (game loop)
     *****************************************************/

	public void run(){
		//thread run event and gameloop
        //long start=System.currentTimeMillis();
        //Thread current=Thread.currentThread();
		//acquire the current thread
        Thread t = Thread.currentThread();

        //process the main game loop thread
        while(t == gameLoop)
        {

        	
	        	//Should not be 0 since you won't get chance to see anything on screen!
	            try{
	            	Thread.sleep(20); // may have to mess with this value to get desired framerate
	            	}
	            
	            catch(InterruptedException e){
	            	e.printStackTrace();
	            	}
	            
	                   
	            //figure out how fast it's running
	            /*
	            if(start+1000<System.currentTimeMillis()){
	                start=System.currentTimeMillis();
	                showStatus("x position: "+player.getX()+"\n"+"  y_position: "+player.getY());
	                count=0;
	            }
	            */
	             //update the internal list of sprites
	             if (!gamePaused()) {
	                 //updateSprites();
	                 //testCollisions();
	            	 
	 	            //checks for active knights to call the knightAI()
	 	            checkForKnights();
	 	            
	 	            //check for collision with existing items
	 	            checkForItems();
	 	            
	 	            //checks the ranges of existing enemies
	 	            checkForEnemies();
	 	            
	 	            //checks the collisions of existing arrows
	 	            checkForArrows();
	             }

	             //allow main game to update if needed
	             gameUpdate();
	             
	            repaint();
        	
        }
    }
	
    /**
     * thread stop event
     *****************************************************/
    public void stop() {
        //kill the game loop
        gameLoop = null;

       
        //gameShutdown(); // this will do any necessary cleanup work
    }
    
    private void resetGame() {
        //restart the music soundtrack
        //wipe out the sprite list to start over!
       //add the saved ship to the sprite list
       //create the enemy sprites
       //reset variables
    	player = null;
    	
    	gameLevel = 1;
    	score = 0;

    	characters.clear();
    	items.clear();
    	players.clear();
        setPlayer();
        setItems();
        setEnemies();
        

        //start off in pause mode again
        pauseGame();
    }
    
    /**
     * process keys that have been pressed for player 
     *****************************************************/
    public void checkInput() {
        if (gameState != GAME_RUNNING) return;
        
        // should eventually move player check input code here when we do more refactoring
    }
    
    /**
     * gameUpdate event passed by game engine
     *****************************************************/
    void gameUpdate() {
        checkInput();

        if (!gamePaused() && characters.size() == 0) { // means all enemies cleared from screen
             // go on to next level
            gameLevel++;
            // add points to player score
            updateScore(500);
            
            gameStartNewLevel();
        }
            else if(!gamePaused() && gameLevel == finalLevel ){
            	 
                 gameState = GAME_WON; // game won since no more levels
        }
    }


	public void paint(Graphics graphics){//Applet paint event
		
		//For the background
	    //int width=getSize().width;//save the window width
	    //int height=getSize().height;//save the window height
	    //g.setColor(Color.black);//set the background color to black
	    //g.fillRect(0,0,width,height);//fill the background with the color  
	    
	    //sets the background and applet size
		Graphics2D g= (Graphics2D) graphics;
		
	    resize(width,height);
	    g.drawImage(imageCache.get("DungeonBackground"), 0, 0, this);
	    
	    
	    //what is the game state?
        if (gameState == GAME_MENU) {
           g.setFont(new Font("Verdana", Font.BOLD, 48));
           g.setColor(Color.YELLOW);
           g.drawString("DUNGEON MASTER", 202, 202);
           g.setColor(new Color(200,30,30));
           g.drawString("DUNGEON MASTER", 200, 200);
           g.setFont(new Font("Times New Roman", Font.ITALIC | Font.BOLD, 20));
           g.drawString("by Team Bowser", 200, 225);

            int x = 270, y = 15;
           g.setFont(new Font("Times New Roman", Font.ITALIC | Font.BOLD, 20));
           g.setColor(Color.YELLOW);
           g.drawString("CONTROLS:", x, ++y*20);
           g.drawString("MOVEMENT - W,A,S,D ", x+20, ++y*20);
           g.drawString("ATTACK - J key", x+20, ++y*20);
           g.drawString("SHOOT - L key", x+20, ++y*20);
           g.drawString("PAUSE - P key", x+20, ++y*20);
           g.drawString("SPECIAL POWER - k key", x+20, ++y*20);

           g.setColor(Color.WHITE);
           g.drawString("POWERUPS INCREASE DAMAGE!", 260, 440);
          

           g.setFont(new Font("Ariel", Font.BOLD, 24));
           g.setColor(Color.BLUE);
           g.drawString("Press ENTER to start", 280, 500);
        }
        else if (gameState == GAME_RUNNING) {
            //draw health/shield bars and meters

    	    //paint the player
        	drawPlayer(g);
        	//paints the items in the items arraylist
    	    drawItems(g);
    	    //Paint the characters in the character arraylist
        	if(characters.size() >0)
        	{
        		drawCharacters(g);
        	}
    	    //paints arrows
    	    drawArrows(g);
    	
    	    //health bar example
    		Shape healthBarBack=new Rectangle2D.Double(40, 545, 100, 20);
    	    g.setColor(Color.red);
    	    g.fill(healthBarBack);//Fills the shape with the set color
    	    Shape healthBarFront=new Rectangle2D.Double(40, 545, player.getHealth(), 20);
    	    g.setColor(Color.green);
    	    g.fill(healthBarFront);//Fills the shape with the set color
    	    
    	    //stamina bar example
    	    Shape shape=new Rectangle2D.Double(40, 565, 100, 20);
    	    g.setColor(Color.black);
    	    g.fill(shape);//Fills the shape with the set color
    	    Shape shape2=new Rectangle2D.Double(40, 565, player.getStamina(), 20);
    	    g.setColor(Color.blue);
    	    g.fill(shape2);//Fills the shape with the set color

            //display the score
           g.setFont(new Font("Verdana", Font.BOLD, 26));
           g.setColor(Color.WHITE);
           g.drawString("Score:" + score, 20, 40);
           g.setColor(Color.RED);
           g.drawString("High Score:" + highScore, 350, 40);
           g.setColor(Color.YELLOW);
           g.drawString("Level:" + gameLevel, 650, 40);
        }
        
        else if(gameState == GAME_OVER) {
           g.setFont(new Font("Verdana", Font.BOLD, 36));
           g.setColor(new Color(200, 30, 30));
           g.drawString("GAME OVER", 270, 200);

           g.setFont(new Font("Arial", Font.CENTER_BASELINE, 24));
           g.setColor(Color.ORANGE);
           g.drawString("Press ENTER to play again", 260, 500);
        }
        
        else if(gameState == GAME_PAUSED) {
            g.setFont(new Font("Verdana", Font.BOLD, 36));
            g.setColor(new Color(200, 30, 30));
            g.drawString("GAME PAUSED", 270, 200);

            g.setFont(new Font("Arial", Font.CENTER_BASELINE, 24));
            g.setColor(Color.ORANGE);
            g.drawString("Press ENTER to continue", 260, 500);
         }
        else if(gameState == GAME_WON) {
        	
            g.setFont(new Font("Verdana", Font.BOLD, 50));
            g.setColor(new Color(200, 30, 30));
            g.drawString("YOU WIN!!!", 270, 300);
          

         }
    }
	
    public void update(Graphics g)
    {
    	 Dimension size = getSize();
    	    if (doubleBuffer == null ||
    	        doubleBuffer.getWidth(this) != size.width ||
    	        doubleBuffer.getHeight(this) != size.height)
    	    {
    	        doubleBuffer = createImage(size.width, size.height);
    	    }


    	    if (doubleBuffer != null) {
    	        // paint to double buffer
    	        Graphics g2 = doubleBuffer.getGraphics();
    	        paint(g2);
    	        g2.dispose();

    	        // copy double buffer to screen
    	        g.drawImage(doubleBuffer, 0, 0, null);
    	    }
    	    else {
    	        // couldn't create double buffer, just paint to screen
    	        paint(g);
    	    }

	       

    }
    
    

    private void drawPlayer(Graphics2D g) {
		player.paint(g);
		
	}
	//draws characters from the characters array list
    private void drawCharacters(Graphics2D g) 
    {
    	for(int i=0;i<characters.size();i++)
        {
    		if(characters.size()==0)
    		{
    			break;
    		}
    		else
    		{
    			characters.get(i).paint(g);
    		}
        	
        }
		
	}
    private void drawItems(Graphics2D g) 
    {
    	for(int i=0;i<items.size();i++)
        {
        	items.get(i).paint(g);
        }
		
	}
    private void drawArrows(Graphics2D g)
    {
    	for(int i=0;i<arrows.size();i++)
        {
        	arrows.get(i).paint(g);
        }
    }

	public static Image getImage(String s){return imageCache.get(s);}
	
	public void setImageCache(){//imageCache.put("",getImage(url,""));
    	URL url=null;
    	try{
    		url=this.getClass().getResource(".");
    		}
    	catch(Exception e){}
		imageCache.put("LinkStandLeft",getImage(url,"../Link/LinkStandLeft.png"));
		imageCache.put("LinkMoveLeft1",getImage(url,"../Link/LinkMoveLeft1.png"));
		imageCache.put("LinkMoveLeft2",getImage(url,"../Link/LinkMoveLeft2.png"));
		imageCache.put("LinkMoveLeft3",getImage(url,"../Link/LinkMoveLeft3.png"));
		imageCache.put("LinkMoveLeft4",getImage(url,"../Link/LinkMoveLeft4.png"));
		imageCache.put("LinkMoveLeft5",getImage(url,"../Link/LinkMoveLeft5.png"));
		imageCache.put("LinkMoveLeft6",getImage(url,"../Link/LinkMoveLeft6.png"));
		imageCache.put("LinkMoveLeft7",getImage(url,"../Link/LinkMoveLeft7.png"));
		imageCache.put("LinkAttackLeft1",getImage(url,"../Link/LinkAttackLeft1.png"));
		imageCache.put("LinkAttackLeft2",getImage(url,"../Link/LinkAttackLeft2.png"));
		imageCache.put("LinkAttackLeft3",getImage(url,"../Link/LinkAttackLeft3.png"));
		imageCache.put("LinkAttackLeft4",getImage(url,"../Link/LinkAttackLeft4.png"));
		imageCache.put("LinkAttackLeft5",getImage(url,"../Link/LinkAttackLeft5.png"));
		imageCache.put("LinkAttackLeft6",getImage(url,"../Link/LinkAttackLeft6.png"));
		imageCache.put("LinkAttackLeft7",getImage(url,"../Link/LinkAttackLeft7.png"));
		imageCache.put("LinkAttackLeft8",getImage(url,"../Link/LinkAttackLeft8.png"));
		imageCache.put("LinkAttackLeft9",getImage(url,"../Link/LinkAttackLeft9.png"));
		imageCache.put("LinkArrowLeft1",getImage(url,"../Link/LinkArrowLeft1.png"));
		imageCache.put("LinkArrowLeft2",getImage(url,"../Link/LinkArrowLeft2.png"));
		imageCache.put("LinkArrowLeft3",getImage(url,"../Link/LinkArrowLeft3.png"));
		imageCache.put("LinkArrowLeft4",getImage(url,"../Link/LinkArrowLeft4.png"));
		imageCache.put("LinkArrowLeft5",getImage(url,"../Link/LinkArrowLeft5.png"));

		imageCache.put("LinkStandRight",getImage(url,"../Link/LinkStandRight.png"));
		imageCache.put("LinkMoveRight1",getImage(url,"../Link/LinkMoveRight1.png"));
		imageCache.put("LinkMoveRight2",getImage(url,"../Link/LinkMoveRight2.png"));
		imageCache.put("LinkMoveRight3",getImage(url,"../Link/LinkMoveRight3.png"));
		imageCache.put("LinkMoveRight4",getImage(url,"../Link/LinkMoveRight4.png"));
		imageCache.put("LinkMoveRight5",getImage(url,"../Link/LinkMoveRight5.png"));
		imageCache.put("LinkMoveRight6",getImage(url,"../Link/LinkMoveRight6.png"));
		imageCache.put("LinkMoveRight7",getImage(url,"../Link/LinkMoveRight7.png"));
		imageCache.put("LinkAttackRight1",getImage(url,"../Link/LinkAttackRight1.png"));
		imageCache.put("LinkAttackRight2",getImage(url,"../Link/LinkAttackRight2.png"));
		imageCache.put("LinkAttackRight3",getImage(url,"../Link/LinkAttackRight3.png"));
		imageCache.put("LinkAttackRight4",getImage(url,"../Link/LinkAttackRight4.png"));
		imageCache.put("LinkAttackRight5",getImage(url,"../Link/LinkAttackRight5.png"));
		imageCache.put("LinkAttackRight6",getImage(url,"../Link/LinkAttackRight6.png"));
		imageCache.put("LinkAttackRight7",getImage(url,"../Link/LinkAttackRight7.png"));
		imageCache.put("LinkAttackRight8",getImage(url,"../Link/LinkAttackRight8.png"));
		imageCache.put("LinkAttackRight9",getImage(url,"../Link/LinkAttackRight9.png"));
		imageCache.put("LinkArrowRight1",getImage(url,"../Link/LinkArrowRight1.png"));
		imageCache.put("LinkArrowRight2",getImage(url,"../Link/LinkArrowRight2.png"));
		imageCache.put("LinkArrowRight3",getImage(url,"../Link/LinkArrowRight3.png"));
		imageCache.put("LinkArrowRight4",getImage(url,"../Link/LinkArrowRight4.png"));
		imageCache.put("LinkArrowRight5",getImage(url,"../Link/LinkArrowRight5.png"));

		imageCache.put("LinkStandUp",getImage(url,"../Link/LinkStandUp.png"));
		imageCache.put("LinkMoveUp1",getImage(url,"../Link/LinkMoveUp1.png"));
		imageCache.put("LinkMoveUp2",getImage(url,"../Link/LinkMoveUp2.png"));
		imageCache.put("LinkMoveUp3",getImage(url,"../Link/LinkMoveUp3.png"));
		imageCache.put("LinkMoveUp4",getImage(url,"../Link/LinkMoveUp4.png"));
		imageCache.put("LinkMoveUp5",getImage(url,"../Link/LinkMoveUp5.png"));
		imageCache.put("LinkMoveUp6",getImage(url,"../Link/LinkMoveUp6.png"));
		imageCache.put("LinkMoveUp7",getImage(url,"../Link/LinkMoveUp7.png"));
		imageCache.put("LinkAttackUp1",getImage(url,"../Link/LinkAttackUp1.png"));
		imageCache.put("LinkAttackUp2",getImage(url,"../Link/LinkAttackUp2.png"));
		imageCache.put("LinkAttackUp3",getImage(url,"../Link/LinkAttackUp3.png"));
		imageCache.put("LinkAttackUp4",getImage(url,"../Link/LinkAttackUp4.png"));
		imageCache.put("LinkAttackUp5",getImage(url,"../Link/LinkAttackUp5.png"));
		imageCache.put("LinkAttackUp6",getImage(url,"../Link/LinkAttackUp6.png"));
		imageCache.put("LinkAttackUp7",getImage(url,"../Link/LinkAttackUp7.png"));
		imageCache.put("LinkAttackUp8",getImage(url,"../Link/LinkAttackUp8.png"));
		imageCache.put("LinkAttackUp9",getImage(url,"../Link/LinkAttackUp9.png"));
		imageCache.put("LinkArrowUp1",getImage(url,"../Link/LinkArrowUp1.png"));
		imageCache.put("LinkArrowUp2",getImage(url,"../Link/LinkArrowUp2.png"));
		imageCache.put("LinkArrowUp3",getImage(url,"../Link/LinkArrowUp3.png"));
		imageCache.put("LinkArrowUp4",getImage(url,"../Link/LinkArrowUp4.png"));
		imageCache.put("LinkArrowUp5",getImage(url,"../Link/LinkArrowUp5.png"));

		imageCache.put("LinkStandDown",getImage(url,"../Link/LinkStandDown.png"));
		imageCache.put("LinkMoveDown1",getImage(url,"../Link/LinkMoveDown1.png"));
		imageCache.put("LinkMoveDown2",getImage(url,"../Link/LinkMoveDown2.png"));
		imageCache.put("LinkMoveDown3",getImage(url,"../Link/LinkMoveDown3.png"));
		imageCache.put("LinkMoveDown4",getImage(url,"../Link/LinkMoveDown4.png"));
		imageCache.put("LinkMoveDown5",getImage(url,"../Link/LinkMoveDown5.png"));
		imageCache.put("LinkMoveDown6",getImage(url,"../Link/LinkMoveDown6.png"));
		imageCache.put("LinkMoveDown7",getImage(url,"../Link/LinkMoveDown7.png"));
		imageCache.put("LinkAttackDown1",getImage(url,"../Link/LinkAttackDown1.png"));
		imageCache.put("LinkAttackDown2",getImage(url,"../Link/LinkAttackDown2.png"));
		imageCache.put("LinkAttackDown3",getImage(url,"../Link/LinkAttackDown3.png"));
		imageCache.put("LinkAttackDown4",getImage(url,"../Link/LinkAttackDown4.png"));
		imageCache.put("LinkAttackDown5",getImage(url,"../Link/LinkAttackDown5.png"));
		imageCache.put("LinkAttackDown6",getImage(url,"../Link/LinkAttackDown6.png"));
		imageCache.put("LinkAttackDown7",getImage(url,"../Link/LinkAttackDown7.png"));
		imageCache.put("LinkAttackDown8",getImage(url,"../Link/LinkAttackDown8.png"));
		imageCache.put("LinkAttackDown9",getImage(url,"../Link/LinkAttackDown9.png"));
		imageCache.put("LinkArrowDown1",getImage(url,"../Link/LinkArrowDown1.png"));
		imageCache.put("LinkArrowDown2",getImage(url,"../Link/LinkArrowDown2.png"));
		imageCache.put("LinkArrowDown3",getImage(url,"../Link/LinkArrowDown3.png"));
		imageCache.put("LinkArrowDown4",getImage(url,"../Link/LinkArrowDown4.png"));
		imageCache.put("LinkArrowDown5",getImage(url,"../Link/LinkArrowDown5.png"));

		imageCache.put("KnightStandLeft",getImage(url,"../Knight/KnightStandLeft.png"));
		imageCache.put("KnightMoveLeft1",getImage(url,"../Knight/KnightMoveLeft1.png"));
		imageCache.put("KnightMoveLeft2",getImage(url,"../Knight/KnightMoveLeft2.png"));
		imageCache.put("KnightMoveLeft3",getImage(url,"../Knight/KnightMoveLeft3.png"));
		imageCache.put("KnightMoveLeft4",getImage(url,"../Knight/KnightMoveLeft4.png"));
		
		imageCache.put("KnightStandRight",getImage(url,"../Knight/KnightStandRight.png"));
		imageCache.put("KnightMoveRight1",getImage(url,"../Knight/KnightMoveRight1.png"));
		imageCache.put("KnightMoveRight2",getImage(url,"../Knight/KnightMoveRight2.png"));
		imageCache.put("KnightMoveRight3",getImage(url,"../Knight/KnightMoveRight3.png"));
		imageCache.put("KnightMoveRight4",getImage(url,"../Knight/KnightMoveRight4.png"));
		
		imageCache.put("KnightStandUp",getImage(url,"../Knight/KnightStandUp.png"));
		imageCache.put("KnightMoveUp1",getImage(url,"../Knight/KnightMoveUp1.png"));
		imageCache.put("KnightMoveUp2",getImage(url,"../Knight/KnightMoveUp2.png"));
		imageCache.put("KnightMoveUp3",getImage(url,"../Knight/KnightMoveUp3.png"));
		imageCache.put("KnightMoveUp4",getImage(url,"../Knight/KnightMoveUp4.png"));
		
		imageCache.put("KnightStandDown",getImage(url,"../Knight/KnightStandDown.png"));
		imageCache.put("KnightMoveDown1",getImage(url,"../Knight/KnightMoveDown1.png"));
		imageCache.put("KnightMoveDown2",getImage(url,"../Knight/KnightMoveDown2.png"));
		imageCache.put("KnightMoveDown3",getImage(url,"../Knight/KnightMoveDown3.png"));
		imageCache.put("KnightMoveDown4",getImage(url,"../Knight/KnightMoveDown4.png"));
		
		imageCache.put("HealthPotion", getImage(url,"../items/BottlePotionRed.gif"));
		imageCache.put("StaminaPotion", getImage(url,"../items/BottlePotionBlue.gif"));
		imageCache.put("Bow", getImage(url,"../items/Bow.png"));
		imageCache.put("Arrow", getImage(url,"../items/Arrow.png"));
		imageCache.put("ArrowUp", getImage(url,"../items/ArrowUp.png"));
		imageCache.put("ArrowDown", getImage(url,"../items/ArrowDown.png"));
		imageCache.put("ArrowRight", getImage(url,"../items/ArrowRight.png"));
		imageCache.put("ArrowLeft", getImage(url,"../items/ArrowLeft.png"));
		
		audioCache.put("ItemPickUp", getAudioClip(url, "../sound/ItemPickUp.wav"));
		audioCache.put("SwordSlash1", getAudioClip(url, "../sound/SwordSlash1.wav"));
		audioCache.put("SwordSlash2", getAudioClip(url, "../sound/SwordSlash2.wav"));
		audioCache.put("EnemyKnightChase", getAudioClip(url, "../sound/EnemyKnightChase.wav"));
		audioCache.put("EnemyKill", getAudioClip(url, "../sound/EnemyKill.wav"));
		audioCache.put("ArrowShoot", getAudioClip(url, "../sound/ArrowShoot.wav"));
		audioCache.put("ArrowHit", getAudioClip(url, "../sound/ArrowHit.wav"));
		//audioCache.put("GameOver", getAudioClip(url, "../music/GameOver.mp3"));
		
		imageCache.put("DungeonBackground", getImage(url,"../background/DungeonBackgroundv2.jpg"));
		imageCache.put("DungeonBackgroundDeres", getImage(url,"../background/DungeonBackgroundDeres.jpg"));
		
    }
		

	@Override
	public void keyPressed(KeyEvent e){//for this method, use the key code to generate movement
	    int keyCode=e.getKeyCode();
	    if(keyCode==cLeft){
	    	if(aLeft==false){
	    		aLeft=true;
	    		player.setMotion("Move","Left");
	    	}
	    }
	    else if(keyCode==cRight){
	    	if(aRight==false){
	    		aRight=true;
	    		player.setMotion("Move","Right");
	    	}
	    }
	    else if(keyCode==cUp){
	    	if(aUp==false){
	    		aUp=true;
	    		player.setMotion("Move","Up");
	    	}
	    }
	    else if(keyCode==cDown){
	    	if(aDown==false){
	    		aDown=true;
	    		//if(player.getDoing()=="Move"){;}
	    		player.setMotion("Move","Down");
	    	}
	    }
	    else if(keyCode==cAttack){
	    	if(aAttack==false){
	    		aAttack=true;
	    		player.setMotion("Attack");
	    		if(System.currentTimeMillis() % 2 == 0)
	    		{
	    			audioCache.get("SwordSlash1").play();
	    		}
	    		else
	    		{
	    			audioCache.get("SwordSlash2").play();
	    		}
	    		boolean deadEnemy = player.attack(player, characters);
	    		if(deadEnemy)
	    		{
	    			audioCache.get("EnemyKill").play();
	    		}
				
	    	}
	    }
	    else if (keyCode==cItem)
	    {
	    	if(aItem==false)
	    	{
	    		aItem = true;
	    		if(player.getBowAttack() && (player.getShootTime() < System.currentTimeMillis() - player.getLastShot())){
	    			player.shoot(player, arrows);
	    			player.setMotion("Shoot");
	    			audioCache.get("ArrowShoot").play();
	    		}
	    	}
	    }
	    else if(keyCode==cPause)
	    {
	    	
	    	   if (gameState == GAME_RUNNING) {
	                pauseGame();
	                gameState = GAME_PAUSED;
	            }
	    	

	    }
	    else if(keyCode == KeyEvent.VK_ENTER)
	    {
            if (gameState == GAME_MENU) {
                //resetGame();
                resumeGame();
                gameState = GAME_RUNNING;
            }
            else if (gameState == GAME_OVER) {
                //resetGame();
            	 if(keyCode == KeyEvent.VK_Y){ // exit or stop game
            	  stop();
            	 }
                resumeGame();
                gameState = GAME_RUNNING;
            }
            else if (gameState == GAME_PAUSED) {
                //start up game again
                resumeGame();
                gameState = GAME_RUNNING;
            }
	    }

	    else if(keyCode == KeyEvent.VK_ESCAPE)
	    {
            if (gameState == GAME_RUNNING) {
                pauseGame();
                gameState = GAME_OVER;
            }
	    }
	    
	    else if(keyCode==cAction)
	    {
	    	// currently doesn't do anything but could open door, treasure chest, inventory, etc in future?
	    	if(aAction==false){
	    	aAction = true;
	    	System.out.println("Action key K pressed .");
	    	
	    	if(player.stamina >= 25){
	    		characters.remove(0); // allows player to kill single enemy with one blow if they have picked up stamina potion
	    		player.stamina-= 25; // remove used up stamina otherwise will be same as god key
	    		// should kill nearest knight/enemy but doesn't  		
	    	}
	    	}
	    	aAction = false; // reset key
	    	
	    }
	    
	    else if(keyCode==cSpecial)
	    {
	    	/**
	    	 * Special key allows you to clear all enemies form screen at once!
	    	 * Basically a cheat or godmode if you like
	    	 */
	    	
	    	if(aSpecial==false){
	    	aSpecial = true;
	    	System.out.println("GodMode!");
	    	characters.clear(); // remove or kill all enemies on screen!
	    	
	    	}
	    	aSpecial = false; // reset key
	    	
	    }
	    	
}

	@Override
	public void keyReleased(KeyEvent e){
		int keyCode=e.getKeyCode();
		if(keyCode==cLeft){
			aLeft=false;
			if((!aRight)&(!aUp)&(!aDown)){
				player.setMotion("Stand");
			}
		}
		else if(keyCode==cRight){
			aRight=false;
			if((!aLeft)&(!aUp)&(!aDown)){
				player.setMotion("Stand");
			}
		}
		else if(keyCode==cUp){
			aUp=false;
			if((!aRight)&(!aLeft)&(!aDown)){
				player.setMotion("Stand");
			}
		}
		else if(keyCode==cDown){
			aDown=false;
			if((!aRight)&(!aUp)&(!aLeft)){
				player.setMotion("Stand");
			}
		}
		else if(keyCode==cAttack){
			aAttack=false;
		}
		else if(keyCode==cItem)
		{
			aItem=false;
		}
	}
	
	//loops through the character array, looking for items
	public void checkForItems()
	{
		for(int i=0;i<items.size();i++)
        {
        	if(items.get(i).getID().equals("HealthPotion"))
        	{
        		boolean itemUsed = player.checkItem(items.get(i));
        		if(itemUsed){
        			System.out.println("Link HP: "+player.getHealth());
    				audioCache.get("ItemPickUp").play();
    				items.remove(items.get(i));
    			}
        	}
        	else if(items.get(i).getID().equals("StaminaPotion"))
        	{
        		boolean itemUsed = player.checkItem(items.get(i));
        		if(itemUsed){
        			System.out.println("Link Stam: "+player.getStamina());
    				audioCache.get("ItemPickUp").play();
    				items.remove(items.get(i));
    			}
        	}
        	else if(items.get(i).getID().equals("Bow"))
        	{
        		boolean itemUsed = player.checkItem(items.get(i));
        		if(itemUsed){
        			System.out.println("Link obtained the Bow.");
    				audioCache.get("ItemPickUp").play();
    				items.remove(items.get(i));
    			}
        	}
        }
		
	}
	

	
	//checks enemies in the character array for collision
	//checks if an enemy has an attackable hit box, depending on link's current direction and location
    //checks to see if the enemy can be attacked and acts accordingly
	public void checkForEnemies()
	{
		for(int i=0;i<characters.size();i++)
        {
        		player.checkHitBox(characters.get(i));
        }
	}
	
	public void checkForArrows()
	{
		for (int i=0; i<characters.size(); i++)
		{
			if(characters.size() == 0)
			{
				break;
			}
			for(int j=0; j<arrows.size(); j++)
			{
				if(arrows.size() == 0)
				{
					break;
				}
				
				if(characters.get(i).getID().equals("Knight"))
				{
					boolean arrowHit = arrows.get(j).checkHitBox(characters.get(i));
					if(arrowHit)
					{
						audioCache.get("ArrowHit").play();
						arrows.remove(j);
						if(characters.get(i).getHealth() == 0)
						{
							characters.remove(i);
							audioCache.get("EnemyKill").play();
						}
					}
				}
			}
		}
	}
	

	
	@Override
	public void keyTyped(KeyEvent arg0){
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseClicked(MouseEvent arg0){
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseEntered(MouseEvent arg0){
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseExited(MouseEvent arg0){
		// TODO Auto-generated method stub
	}

	@Override
	public void mousePressed(MouseEvent arg0){
		// TODO Auto-generated method stub
	}

	@Override
	public void mouseReleased(MouseEvent arg0){
		// TODO Auto-generated method stub
	}
	
	//Checks for knights in the character array and performs AI functionality
	public void checkForKnights()
	{
			for(int i=0;i<characters.size();i++)
	        {
	        	if(characters.get(i).getID().equals("Knight"))
	        	{
	        		knightAI(characters.get(i));
	        	}
	        }
		
	}
	
	public void knightAI(Character character){
		Knight knight = (Knight) character;
		double distance = Math.sqrt((player.getX()-knight.getX()) * 
				                    (player.getX()-knight.getX()) +
						            (player.getY()-knight.getY()) *
						            (player.getY()-knight.getY()));
		
		if((distance <= 200 && player!=null) || (knight.getShot()))
		{
			if((knight).getReset())
			{
				audioCache.get("EnemyKnightChase").play();
				knight.setReset(false);
				
			}
			//Match Y position of characters
			//Player is below knight
			if(player.getY() - knight.getY() > 20)
			{
				knight.setMotion("Move", "Down");
			}
			//Player is above knight
			else if(player.getY() - knight.getY() < -20){
				knight.setMotion("Move", "Up");
			}
			//Player is close to Y position of the knight
			else if(player.getX() - knight.getX() > 20)
			{
				//Player is to the Right of the knight
				knight.setMotion("Move", "Right");
			}	
			//Player is to the Left of the knight
			else if(player.getX() - knight.getX() < -20)
			{
				knight.setMotion("Move", "Left");
			}
			//Player is close to the Knight.  ATTACK!!
			else
			{
				if(knight.getSwingTime() < System.currentTimeMillis() - knight.getLastSwing()) {
					knight.setMotion("Attack");
					boolean deadLink = knight.attack(knight, characters, player);
					if(deadLink){ //Link is dead
						  
	                            gameState = GAME_OVER;
	                           
	                            // reset stuff 
	                            resetGame();
	                        
						
					}
					knight.setLastSwing(System.currentTimeMillis());
				}
				
			}
			//Match X position of characters
		}
		//Knight is out of range
		else
		{
			knight.setReset(true);
			if(knight.getDirection().equals("Up") || knight.getDirection().equals("Down") )
			{
				knight.setMotion("Stand", "Left");
			}
			if(Math.abs(knight.getInitialX() - knight.getX()) >= 100 && !(knight.getDoing().equals("Stand")))
			{
	        	knight.setMotion("Stand");
	        	knight.setTimer();
	        }
			else if(knight.getDoing().equals("Stand") &&
	           System.currentTimeMillis()- knight.getTimer() > 1000)
			{
	        	if(knight.getDirection().equals("Left"))
	        	{
	        		knight.setMotion("Move", "Right");
	        	}
	        	else if(knight.getDirection().equals("Right"))
	        	{
	        		knight.setMotion("Move", "Left");
	        	}
	        	knight.setInitialX();
	        }
		}
		
	}
	
    /**
     * increment the score and update high score if needed
     *****************************************************/
    public void updateScore(int howmuch) {
        score += howmuch;
        if (score > highScore)
            highScore = score;
    }
}